package com.tanhua.server.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @ClassName :  RedisCacheInterceptor
 * @Author : Tenebrous
 * @Date: 2020/12/11 15:13
 * @Description : 缓存
 */
@Component
public class RedisCacheInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 缓存开启开关注入
     */
    @Value("${tanhua.cache.enable}")
    private Boolean enable;

    private static ObjectMapper mapper = new ObjectMapper();

    /**
     * 拦截前
     * @param request           请求
     * @param response          响应
     * @param handler           处理
     * @return                  boolean
     * @throws Exception        异常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 判断是否开启缓存
        if (!enable) {
            //未开启缓存，放行，不拦截
            return true;
        }

        // 否则实施拦截
        String get = "GET";
        String post = "POST";
        // 获取请求的方法名
        String method = request.getMethod();
        // 判断获取的请求方法名是否为get，post(忽略大小写)
        if (!StringUtils.equalsAnyIgnoreCase(method, get, post)) {
            // 非GET、POST的请求不进行缓存处理，放行
            return true;
        }

        // 通过缓存做命中，查询redis，redisKey ?  组成：md5（请求的url + 请求参数）
        String redisKey = createRedisKey(request);
        // 根据key去Redis中取数据
        String data = this.redisTemplate.opsForValue().get(redisKey);
        // Redis中没有时
        if (StringUtils.isEmpty(data)) {
            // 缓存未命中 放行
            return true;
        }

        // 将data数据进行响应
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        // 响应前端
        response.getWriter().write(data);
        return false;
    }

    /**
     * Redis中key的生成方法
     *      设计规则；请求路径+参数 作为key
     * @param request           请求对象
     * @return                  String类型的Redis  key
     * @throws Exception        异常
     */
    public static String createRedisKey(HttpServletRequest request) throws
            Exception {
        // 获取请求的URL
        String paramStr = request.getRequestURI();
        // 获取请求的参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        // 如果请求的参数为空，代表是POST请求
        if (parameterMap.isEmpty()) {
            //请求体的数据只能读取一次，需要进行包装Request进行解决
            paramStr += IOUtils.toString(request.getInputStream(), "UTF-8");
        } else {
            // 不为空，为GET请求，直接将参数序列化
            paramStr += mapper.writeValueAsString(request.getParameterMap());
        }

        // 获取Token的头信息
        String authorization = request.getHeader("Authorization");
        if (StringUtils.isNotEmpty((authorization))) {
            // 不为空时，与前面的请求参数序列化后的字符串拼接
            paramStr += "_" + authorization;
        }

        // 返回Redis的key
        return "SERVER_DATA_" + DigestUtils.md5Hex(paramStr);
    }
}
